﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Lrd.Template.Core.Infrastructure.Entity;
using Lrd.Template.Core.Infrastructure.Enums;
using Lrd.Template.Core.Infrastructure.Extensions;
using Lrd.Template.Core.Infrastructure.Helps;
using Lrd.Template.Core.Infrastructure.Net;

namespace Lrd.Template.Core.Infrastructure.EntityHistory
{
    public class AuditEntityHelper : IAuditEntityHelper
    {


 


        public ICollection<AuditEntityEntry> GetAuditEntityEntry(ICollection<EntityEntry> entityEntries)
        {


            List<AuditEntityEntry> auditEntityEntries = new List<AuditEntityEntry>();
            EntityState[] states = { EntityState.Added, EntityState.Modified, EntityState.Deleted };
            foreach (var entity in entityEntries.Where(m => m.Entity != null && states.Contains(m.State)).ToArray())
            {
                auditEntityEntries.Add(this.CreateAuditEntity(entity));
            }
            return auditEntityEntries;

        }

        public AuditEntityEntry CreateAuditEntity(EntityEntry entityEntry)
        {

            var entity = entityEntry.Entity;
            var type = entity.GetType();
            var description = type.ToDescription(); //得到实体上特性
            EntityChangeType changeType;
            switch (entityEntry.State)
            {

                case EntityState.Added:
                    changeType = EntityChangeType.Insert;
                    break;
                case EntityState.Deleted:
                    changeType = IsDeleted(entityEntry) ? EntityChangeType.Deleted : EntityChangeType.Updated;
                    break;
                case EntityState.Modified:
                    changeType = IsDeleted(entityEntry) ? EntityChangeType.Deleted : EntityChangeType.Updated;
                    break;
                case EntityState.Detached:
                case EntityState.Unchanged:
                default:
                    return null;
            }



            var entityKey = GetEntityKey(entity);
            if (entityKey == null && changeType != EntityChangeType.Insert)
            {
                //Logger.Error("EntityID空值!");
                return null;
            }
            AuditEntityEntry audit = new AuditEntityEntry();
            audit.ChangeType = changeType;
            audit.EntityEntry = entity;
            audit.EntityKey = entityKey;
            audit.TypeName = type.FullName;
            audit.Name = description;
            audit.PropertyEntries = GetPropertyEntitys(entityEntry);
            return audit;
        }


        /// <summary>
        /// 得到属性实体ss
        /// </summary>
        /// <param name="entityEntry"></param>
        /// <returns></returns>
        private ICollection<AuditEntityProperty> GetPropertyEntitys(EntityEntry entityEntry)
        {
            List<AuditEntityProperty> auditEntityProperties = new List<AuditEntityProperty>();
            var properties = entityEntry.Metadata.GetProperties();
            var isCreated = IsCreated(entityEntry);
            var isDeleted = IsDeleted(entityEntry);
            foreach (var property in properties.Where(p => !p.IsConcurrencyToken))
            {
                var name = property.Name;
                var propertyEntry = entityEntry.Property(property.Name);
                //if (property.IsPrimaryKey())
                //{
                //    var key = entityEntry.State == EntityState.Deleted
                //        ? propertyEntry.OriginalValue?.ToString()
                //        : propertyEntry.CurrentValue?.ToString();
                //}


                var displayName = propertyEntry.Metadata.PropertyInfo.ToDescription();
                AuditEntityProperty auditEntityProperty = new AuditEntityProperty();
                auditEntityProperty.DisplayName = displayName;
                auditEntityProperty.PropertyName = name;
                auditEntityProperty.PropertyTypeName = property.ClrType.FullName;
                string currentValue = propertyEntry.CurrentValue?.ToString();
                string originalValue = propertyEntry.OriginalValue?.ToString();
                auditEntityProperty.NewValue = isDeleted ? null : currentValue;
                auditEntityProperty.OriginalValue = isCreated ? null : originalValue;

                if (entityEntry.State == EntityState.Modified&& currentValue == originalValue)
                {
                    continue;
                }
  
                auditEntityProperties.Add(auditEntityProperty);
 

            }
            return auditEntityProperties;
        }
        /// <summary>
        /// 得到实体主键 
        /// </summary>
        /// <param name="entityAsObj"></param>
        /// <returns></returns>
        private string GetEntityKey(object entityAsObj)
        {
            return entityAsObj
                .GetType().GetProperty("Id")?
                .GetValue(entityAsObj)?
                .ToJson();
        }
        private bool IsCreated(EntityEntry entityEntry)
        {
            return entityEntry.State == EntityState.Added;
        }


        private bool IsDeleted(EntityEntry entityEntry)
        {
            if (entityEntry.State == EntityState.Deleted)
            {
                return true;
            }

            var entity = entityEntry.Entity;
            return entity is ISoftDelete && entity.As<ISoftDelete>().IsDeleted;
        }




        public void Save(AuditChangeEntry audit)
        {
            foreach (var entityEntrie in audit.AuditEntityEntries.Where(o => o != null))
            {
                // EntityEntry entityEntry = entityEntrie.EntityEntry.As<EntityEntry>(); 
                if (entityEntrie.ChangeType == EntityChangeType.Insert)
                {
                    entityEntrie.EntityKey = GetEntityKey(entityEntrie.EntityEntry);
                    var property = entityEntrie.PropertyEntries.Where(o => o.PropertyName == "Id").FirstOrDefault();
                    if (property != null)
                    {
                        dynamic entity = entityEntrie.EntityEntry;
                        property.NewValue = entity.Id.ToString();
                    }
                }
            }
        }
    }
}
